#! /bin/sh
#
#   Bacula(R) - The Network Backup Solution
#
#   Copyright (C) 2000-2023 Kern Sibbald
#
#   The original author of Bacula is Kern Sibbald, with contributions
#   from many others, a complete list can be found in the file AUTHORS.
#
#   You may use this file and others of this release according to the
#   license defined in the LICENSE file, which includes the Affero General
#   Public License, v3.0 ("AGPLv3") and some additional permissions and
#   terms pursuant to its AGPLv3 Section 7.
#
#   This notice must be preserved when any source code is 
#   conveyed and/or propagated.
#
#   Bacula(R) is a registered trademark of Kern Sibbald.
#
# bacula-ctl-fd This shell script takes care of starting and stopping
#		the bacula File daemon.
#
#   This is pretty much watered down version of the RedHat script
#   that works on Solaris as well as Linux, but it won't work everywhere.
#
# description: The Leading Open Source Backup Solution.
#

PSCMD="@PSCMD@"
PS="ps"

#
# On Solaris, you may need to use nawk, or alternatively,
#  add the GNU binaries to your path, such as /usr/xpg4/bin
#
AWK=@AWK@

# All these are not *really* needed but it makes it
#  easier to "steal" this code for the development 
#  environment where they are different.
#  
BACFDBIN=@sbindir@
BACFDCFG=@sysconfdir@
PIDDIR=@piddir@
SUBSYSDIR=@subsysdir@

FD_PORT=@fd_port@

FD_USER=@fd_user@
FD_GROUP=@fd_group@
Bacula="@BACULA@"
PIDOF=@PIDOF@	

# A function to stop a program.
killproc() {
   RC=0
   # Test syntax.
   if [ $# = 0 ]; then
      echo "Usage: killproc {program} {port} [signal]"
      return 1
   fi

   notset=0
   # check for third arg to be kill level
   if [ "$3" != "" ] ; then
      killlevel=$3
   else
      notset=1
      killlevel="-9"
   fi

   # Get base program name
   base=`basename $1`

   # Find pid.
   pid=`pidofproc $base $2`

   # Kill it.
   if [ "$pid" != "" ] ; then
      if [ "$notset" = "1" ] ; then
	 if ${PS} -p "$pid">/dev/null 2>&1; then
	     # TERM first, then KILL if not dead
	     kill -TERM $pid 2>/dev/null
	     sleep 1
	     if ${PS} -p "$pid" >/dev/null 2>&1 ; then
		 sleep 1
		 if ${PS} -p "$pid" >/dev/null 2>&1 ; then
		     sleep 3
		     if ${PS} -p "$pid" >/dev/null 2>&1 ; then
			 kill -KILL $pid 2>/dev/null
		     fi
		 fi
	     fi
	  fi
	  ${PS} -p "$pid" >/dev/null 2>&1
	  RC=$?
	  [ $RC -eq 0 ] && failure "$base shutdown" || success "$base shutdown"
      #    RC=$((! $RC))
      # use specified level only
      else
	 if ${PS} -p "$pid" >/dev/null 2>&1; then
	    kill $killlevel $pid 2>/dev/null
	    RC=$?
	    [ $RC -eq 0 ] && success "$base $killlevel" || failure "$base $killlevel"
	 fi
      fi
   else
      failure "$base shutdown"
   fi
   # Remove pid file if any.
   if [ "$notset" = "1" ]; then
      rm -f ${PIDDIR}/$base.$2.pid
   fi
   return $RC
}

# A function to find the pid of a program.
pidofproc() {
   pid=""
   # Test syntax.
   if [ $# = 0 ] ; then
      echo "Usage: pidofproc {program}"
      return 1
   fi

   # Get base program name
   base=`basename $1`

   # First try PID file
   if [ -f ${PIDDIR}/$base.$2.pid ] ; then
      pid=`head -n 1 ${PIDDIR}/$base.$2.pid`
      if [ "$pid" != "" ] ; then
	 echo $pid
	 return 0
      fi
   fi

   # Next try "pidof"
   if [ -x ${PIDOF} ] ; then
      pid=`${PIDOF} $1`
   fi
   if [ "$pid" != "" ] ; then
      echo $pid
      return 0
   fi

   # Finally try to extract it from ps
   pid=`${PSCMD} | grep $1 | ${AWK} '{ print $1 }' | tr '\n' ' '`
   echo $pid
   return 0
}

status() {
   pid=""
   # Test syntax.
   if [ $# = 0 ] ; then
       echo "Usage: status {program} {port}"
       return 1
   fi

   # Get base program name
   base=`basename $1`

   # First try "pidof"
   if [ -x ${PIDOF} ] ; then
      pid=`${PIDOF} $1`
   fi
   if [ "$pid" != "" ] ; then
      echo "$base (pid $pid) is running..."
      return 0
   else
      pid=`${PSCMD} | ${AWK} 'BEGIN { prog=ARGV[1]; ARGC=1 } 
	    { if ((prog == $2) || (("(" prog ")") == $2) ||
		 (("[" prog "]") == $2) ||
		 ((prog ":") == $2)) { print $1 ; exit 0 } }' $1`
      if [ "$pid" != "" ] ; then
	 echo "$base (pid $pid) is running..."
	 return 0
      fi
   fi

   # Next try the PID files
   if [ -f ${PIDDIR}/$base.$2.pid ] ; then
      pid=`head -n 1 ${PIDDIR}/$base.$2.pid`
      if [ "$pid" != "" ] ; then
	 echo "$base dead but pid file exists"
	 return 1
      fi
   fi
   # See if the subsys lock exists
   if [ -f ${SUBSYSDIR}/$base ] ; then
      echo "$base dead but subsys locked"
      return 2
   fi
   echo "$base is stopped"
   return 3
}

success() {
   return 0
}

failure() {
   rc=$?
   return $rc
}

OS=`uname -s`

# if /lib/tls exists, force Bacula to use the glibc pthreads instead
if [ -d "/lib/tls" -a $OS = "Linux" -a `uname -r | cut -c1-3` = "2.4" ] ; then
   export LD_ASSUME_KERNEL=2.4.19
fi

case "$1" in
   start)
      [ -x ${BACFDBIN}/bacula-fd ] && {
	 echo "Starting the $Bacula File daemon"
	 OPTIONS=''
	 if [ "${FD_USER}" != '' ]; then
	    OPTIONS="${OPTIONS} -u ${FD_USER}"
	 fi

	 if [ "${FD_GROUP}" != '' ]; then
	    OPTIONS="${OPTIONS} -g ${FD_GROUP}"
	 fi

	 if [ "x${VALGRIND_FD}" = "x1" ]; then
	    valgrind --leak-check=full ${BACFDBIN}/bacula-fd $2 $3 ${OPTIONS} -v -c ${BACFDCFG}/bacula-fd.conf
	 else
	    ${BACFDBIN}/bacula-fd $2 $3 ${OPTIONS} -v -c ${BACFDCFG}/bacula-fd.conf
	 fi
      }
      ;;

   stop)
      # Stop the FD first so that SD will fail jobs and update catalog
      [ -x ${BACFDBIN}/bacula-fd ] && {
	 echo "Stopping the $Bacula File daemon"
	 killproc ${BACFDBIN}/bacula-fd ${FD_PORT} $2
      }
      ;;

   restart)
      $0 stop
      sleep 5
      $0 start
      ;;

   status)
      [ -x ${BACFDBIN}/bacula-fd ] && status ${BACFDBIN}/bacula-fd  ${FD_PORT}
      ;;

   *)
      echo "Usage: $0 {start|stop|restart|status}"
      exit 1
      ;;
esac
exit 0
